package application;


import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;


import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.core.StopAnalyzer;
import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
import org.apache.lucene.analysis.en.EnglishAnalyzer;
import org.apache.lucene.analysis.standard.ClassicAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.similarities.AfterEffect;
import org.apache.lucene.search.similarities.AfterEffectB;
import org.apache.lucene.search.similarities.BM25Similarity;
import org.apache.lucene.search.similarities.BasicModel;
import org.apache.lucene.search.similarities.BasicModelBE;
import org.apache.lucene.search.similarities.DFRSimilarity;
import org.apache.lucene.search.similarities.DefaultSimilarity;
import org.apache.lucene.search.similarities.Distribution;
import org.apache.lucene.search.similarities.DistributionLL;
import org.apache.lucene.search.similarities.IBSimilarity;
import org.apache.lucene.search.similarities.Lambda;
import org.apache.lucene.search.similarities.LambdaDF;
import org.apache.lucene.search.similarities.Normalization;
import org.apache.lucene.search.similarities.NormalizationH1;
import org.apache.lucene.search.similarities.Similarity;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

import application.SearchOutCome;

public class ImageSearchLogic {
    private int SIZE = 256;
    // Red, Green, Blue  or Y, Cb, Cr 
    private int NUMBER_OF_COLOURS = 3;

    private final int Y = 0;
    private final int Cb = 1;
    private final int Cr = 2;
    private final int ALPHA = 0;
    private final int BETA = 1;
    private int dim = 16;
    private double tColor = 5;
	private BufferedImage buffered1;
	private BufferedImage buffered2;
	
	private double[][] perceptualArr;
	
	//edge
	int magitude = 23;
	int gradient = 16;
	
	//edge & CCV combine threshold
	double threshold = 0.9;
    
	public ImageSearchLogic(){
		precomputePerceptualSimilarity();
	}
    /**
     * CCV Logic
     * 
     */
    
	//get CCV alpha and beta for discretized color of the image
	public double[][] getCCV(BufferedImage image) {
		int imHeight = image.getHeight();
        int imWidth = image.getWidth();
        int t = 25;
        double[][] bins = new double[dim*dim*dim][2];
        int step = SIZE / dim;
        Raster raster = image.getRaster();
        
        double[][][] colorBin = new double[imWidth][imHeight][NUMBER_OF_COLOURS];
        
        //extract color from image, convert to ycbcr representation
        for(int i = 0; i < imWidth; i++)
        {
            for(int j = 0; j < imHeight; j++)
            {
            	// rgb->ycrcb
            	int r = raster.getSample(i,j,0);
            	int g = raster.getSample(i,j,1);
            	int b = raster.getSample(i,j,2);
            	int y  = (int)( 0.299   * r + 0.587   * g + 0.114   * b);
        		int cb = (int)(-0.16874 * r - 0.33126 * g + 0.50000 * b);
        		int cr = (int)( 0.50000 * r - 0.41869 * g - 0.08131 * b);
        		
        		colorBin[i][j][Y] = adjust(y);
        		colorBin[i][j][Cb] = adjust(cb);
        		colorBin[i][j][Cr] = adjust(cr);
            }
        }
        
        //blur the image be taking the average color
        for(int i = 0; i < imWidth; i++)
        {
            for(int j = 0; j < imHeight; j++)
            {
            	int count = 0;
            	double ySum = 0;
            	double cbSum = 0;
            	double crSum = 0;
            	for(int k = -1; k < 2; ++k){
                    for(int l = -1; l < 2; ++l){
                        if(i + k < 0) continue;
                        if(j + l < 0) continue;
                        if(i + k >= imWidth) continue;
                        if(j + l >= imHeight) continue;
                        count++;
                        ySum += colorBin[i+k][j+l][Y];
                        cbSum += colorBin[i+k][j+l][Cb];
                        crSum += colorBin[i+k][j+l][Cr];
                    }
                }
            	
            	colorBin[i][j][Y] = ySum/count;
            	colorBin[i][j][Cb] = cbSum/count;
            	colorBin[i][j][Cr] = crSum/count;
            }
        }
        
        //Discretize the color-space
        int[][][] colorBinDisc = new int[imWidth][imHeight][NUMBER_OF_COLOURS];
        for(int i = 0; i < imWidth; i++)
        {
            for(int j = 0; j < imHeight; j++)
            {
            	colorBinDisc[i][j][Y] = (int)colorBin[i][j][Y]/step;
            	colorBinDisc[i][j][Cb] = (int)colorBin[i][j][Cb]/step;
            	colorBinDisc[i][j][Cr] = (int)colorBin[i][j][Cr]/step;
            }
        }
        
        //Classify each pixel either as coherent or incoherent - two pass algorithm 
        int[][] lbl = new int[imWidth][imHeight];
        int id = 0;
        for (int y = 0; y < imHeight;  ++y) {
        	for (int x = 0; x < imWidth; ++x) {
        		int col[] = colorBinDisc[x][y];
        		if(y > 0) {
        			if(x > 0){
        				if(isEqual(col, colorBinDisc[x-1][y-1])){
        					lbl[x][y] = lbl[x-1][y-1];
        					continue;
        				}
        			}
        			if(isEqual(col, colorBinDisc[x][y-1])){
        				lbl[x][y] = lbl[x][y - 1];
        				continue;
        			}
        			if(x < imWidth - 1){
        				if(isEqual(col, colorBinDisc[x+1][y-1])){
        					lbl[x][y] = lbl[x + 1][y - 1];
        					continue;
        				}
        			}
        		}
        		
        		if(x > 0) {
        			if (isEqual(col, colorBinDisc[x-1][y])){
        				lbl[x][y] = lbl[x - 1][y];
        				continue;
        			}
        		}
                lbl[x][y] = id;
                ++id;
        	}
        }
        
        //counting
        int[] count = new int[id];
        int[][] color = new int[id][NUMBER_OF_COLOURS];
        for(int x = 0; x < imWidth; ++x){
            for(int y = 0; y < imHeight; ++y){
                count[lbl[x][y]]++;
                color[lbl[x][y]] = colorBinDisc[x][y];
            }
        }
        int sum=0;
        int alphaCount = 0;
        int betaCount = 0;
        for (int i = 0;i < id; ++i) {
    		int y = color[i][Y];
    		int cb = color[i][Cb];
    		int cr = color[i][Cr];
        	if (count[i]<t) {
        		bins[y*dim*dim+cb*dim+cr][BETA] += (double)count[i];
        		betaCount+=count[i];
        	}
        	else {
        		bins[y*dim*dim+cb*dim+cr][ALPHA] += (double)count[i];
        		alphaCount+=count[i];
        	}
        	
        }
        for (int i =0; i<dim*dim*dim;i++){
        	bins[i][ALPHA] /= alphaCount;
        	bins[i][BETA] /= betaCount;
        }
        //System.out.println(sum);
        //System.out.println(imHeight*imWidth);
        return bins;
	}
	
	private double adjust(int x) {
		if(x<0)
			return 0;
		else if (x>SIZE)
			return SIZE;
		else
			return x;
	}

	private double normalizedSim(double[][] q, double[][] d, int i, int option){
		double nSim;
		if (Math.max(q[i][option], d[i][option])!=0)
			nSim = q[i][option]*(1 - Math.abs(q[i][option] - d[i][option])/Math.max(q[i][option], d[i][option]));
		else
			nSim = 0;
		return nSim;
	}
	
	private double perceptualSimilarity(int colorI, int colorJ) {
		double d = perceptualArr[colorI][colorJ];
		if (d > tColor)
			return 0;
		else
			return (1 - d/tColor);
	}
	
	private void precomputePerceptualSimilarity(){
		perceptualArr = new double[dim*dim*dim][dim*dim*dim];
		for(int i = 0; i < perceptualArr.length; i++){
			for(int j = i; j < perceptualArr[0].length; j++){
				perceptualArr[i][j] = distance(i,j);
				perceptualArr[j][i] = perceptualArr[i][j];
			}
		}
	}
	
	private double distance(int i, int j){
		int y1 = i/(dim*dim);
		int cb1 = (i%(dim*dim))/dim;
		int cr1 = i%dim;
		
		int y2 = j/(dim*dim);
		int cb2 = (j%(dim*dim))/dim;
		int cr2 = j%dim;
		
		return Math.sqrt(Math.pow(y1-y2,2) + Math.pow(cb1-cb2,2) + Math.pow(cr1-cr2,2));
	}
	
	private boolean isEqual(int[] col, int[] is) {
		if (col[Y] != is[Y]||col[Cb] != is[Cb]||col[Cr] != is[Cr])
			return false;
		else
			return true;
	}

	
	private double calculateCCVSimilarity(double[][] ccvBin1, double[][] ccvBin2) {

		
		double simALPHA[] = new double[dim*dim*dim];
		double simBETA[] = new double[dim*dim*dim];
		double simSumALPHA = 0;
		double simSumBETA = 0;
		
		for (int i =0;i<dim*dim*dim;i++) {
			simALPHA[i] += normalizedSim(ccvBin1, ccvBin2, i, ALPHA);
			simBETA[i] += normalizedSim(ccvBin1, ccvBin2, i, BETA);
		}

			
		for (int i = 0;i<dim*dim*dim;i++) {
			for (int j = i+1; j<dim*dim*dim;j++) {
				if (simALPHA[i]*simALPHA[j]!=0)
					simSumALPHA += simALPHA[i]*simALPHA[j]*perceptualSimilarity(i,j);
				if (simBETA[i]*simBETA[j]!=0)
					simSumBETA +=simBETA[i]*simBETA[j]*perceptualSimilarity(i,j);
			}
		}
			
		return (0.8*simSumALPHA+0.2*simSumBETA);
	}
	
	/**
	 * Index Logic
	 * 
	 */
	
	public void indexTag(File folder) throws IOException{
		File indexFile = new File("tag.txt");
		BufferedWriter output = new BufferedWriter(new FileWriter(indexFile));
		File[] listOfFiles = folder.listFiles();
		HashMap<String,ArrayList<String>> map = new HashMap<String,ArrayList<String>>();
		for(int i=0; i<listOfFiles.length; i++){
			try{
				File file = listOfFiles[i];
				if(file.isFile() && file.getName().endsWith(".txt")){
					ArrayList<String>content = readTextFile(file);
					for(int j=0;j<content.size();j++){
						if(map.get(content.get(j)) == null){
							ArrayList<String> lst = new ArrayList<String>();
							lst.add(file.getName());
							map.put(content.get(j), lst);
						}else{
							map.get(content.get(j)).add(file.getName());
						}
					}
				}
			}
			catch(Exception E){
				System.out.println(E.getMessage());
			
				continue;
			}
		}
		for(Map.Entry<String, ArrayList<String>> entry: map.entrySet()){
			output.write(entry.getKey()+"\t");
			for(int i=0; i<entry.getValue().size();i++){
				output.write(entry.getValue().get(i)+" ");
			}
			output.write("\n");
		}
	}
	
	public ArrayList<String> readTextFile(File file) throws IOException{
		ArrayList<String> result = new ArrayList<String>();
		BufferedReader br = new BufferedReader(new FileReader(file));
		String line;
		while((line = br.readLine())!=null){
			if(line.split("").length>1)
				result.add(line);
		}
		return result;
	}
	
	
	public void indexImage(File folder) throws IOException{
		File indexFile = new File("index.txt");
		File overAllInfoFile = new File("info.txt");
		BufferedWriter output = new BufferedWriter(new FileWriter(indexFile));
		File[] listOfFiles = folder.listFiles();
		int count=0;
		for(int i=0; i<listOfFiles.length; i++){
			try{
				File file = listOfFiles[i];
				if(file.isFile() && file.getName().endsWith(".jpg")){
					double[] edgeInfo = getEdge(ImageIO.read(file));
					double[][] ccvInfo = getCCV(ImageIO.read(file));
					output.write(file.getName()+"\n");
					//System.out.println(file.getName());
					output.write("edge\n");
					for(int j =0; j < edgeInfo.length; j++){
						output.write(edgeInfo[j]+" ");
					}
					output.write("\n");
					output.write("ccv\n");
					for(int j=0; j < ccvInfo[0].length; j++){
						for(int k=0; k < ccvInfo.length; k++){
							output.write(ccvInfo[k][j]+" ");
						}
						output.write("\n");
					}
					count++;
				}
			}
			catch(Exception E){
				E.printStackTrace();
				continue;
			}
		}
		output.flush();
		output.close();
		output = new BufferedWriter(new FileWriter(overAllInfoFile));
		output.write(""+count);
		output.flush();
	}
	
	/**
	 * Search Logic
	 * 
	 */
	
	public List <SearchOutCome> searchLibrary(BufferedImage br1, ArrayList<SearchOutCome>feedbackTags){
		//for(int i= 0; i< feedbackTags.size(); i++)
		//	System.out.println(feedbackTags.get(i).fileName +" "+ feedbackTags.get(i).score);
		File indexFile = new File("index.txt");
		File infoFile = new File("info.txt");
		try {
			BufferedReader reader = new BufferedReader(new FileReader(infoFile));
			int fileCount = Integer.parseInt(reader.readLine());
			List <SearchOutCome> searchResult = new ArrayList<SearchOutCome>();
			reader = new BufferedReader(new FileReader(indexFile));
			double[] edge1 = getEdge(br1);
			double[][] ccv1 = getCCV(br1);
			// proferm textbased search
			Map<String, Double>textSearchResult = new HashMap<String, Double>();
			if(feedbackTags != null){
				//textSearchResult = searchTag(feedbackTags);
				String query = "";
				for(int i = 0; i < feedbackTags.size(); i++){
					query+=feedbackTags.get(i).fileName+" ";
				}
				if(!query.equals("")){
					textSearchResult = luceneSearch(20, query);
					for (Map.Entry<String, Double> entry : textSearchResult.entrySet())
					{
					    System.out.println(entry.getKey() + "/" + entry.getValue());
					}
				}
			}
			for(int i = 0; i < fileCount; i++){
				String fileName = reader.readLine();
				String edgeTitle = reader.readLine();
				double[] edgeHist = rebuildEdgeHist(reader.readLine());
				String ccvTitle = reader.readLine();
				double[][] ccvHist = rebuildCVVHist(reader.readLine(), reader.readLine());
				//System.out.print(fileName);
				double imageScore = computeSimilarity(edge1, edgeHist, ccv1, ccvHist);
				Double tagScore = textSearchResult.get(fileName.substring(0, fileName.length()-4)+".txt");
				if(tagScore == null)
					searchResult.add(new SearchOutCome(fileName, imageScore));
				else
					searchResult.add(new SearchOutCome(fileName, imageScore+100* tagScore));
			}
			Collections.sort(searchResult);
			return searchResult;
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}

	public Map<String, Double> searchTag(ArrayList<SearchOutCome> tags) throws IOException{
		Map<String, Double> result = new HashMap<String, Double>();
		File indexFile = new File("tag.txt");
		List <SearchOutCome> searchResult = new ArrayList<SearchOutCome>();
		BufferedReader reader = new BufferedReader(new FileReader(indexFile));
		String line = "";
		while((line = reader.readLine()) != null) {
			String[] tokens = line.split("\t");
			for(int i = 0; i< tags.size(); i++){
				if(tokens[0].equals(tags.get(i).fileName)){
					//System.out.println("toeken" + 0 +" is " +tokens[0]);
					tokens = tokens[1].split(" ");
					for(int j = 0; j< tokens.length; j++){
					//	System.out.println("toeken" + j +" is " +tokens[j]);
						Double freq = result.get(tokens[j]);
						result.put(tokens[j], (freq==null)? tags.get(i).score : freq + tags.get(i).score);
					}
				}
			}
		}
		return result;
	}
	
	public double[] rebuildEdgeHist(String str){
		String[] tokens = str.split(" ");
		double[] result = new double[tokens.length];
		for(int i = 0; i < tokens.length; i++)
			result[i] = Double.parseDouble(tokens[i]);
		
		return result;
	}
	public double[][] rebuildCVVHist(String str1, String str2){
		String[] tokens1 = str1.split(" ");
		String[] tokens2 = str2.split(" ");
		double[][] result = new double[tokens1.length][2];
		for(int i=0; i < tokens1.length; i++){
			result[i][0] = Double.parseDouble(tokens1[i]);
			result[i][1] = Double.parseDouble(tokens2[i]);
		}
		return result;
	}
	
	
	/**
	 * Edge Similarity Logic
	 * 
	 */
	public double calculateEdgeSimilarity(BufferedImage buffered1, BufferedImage buffered2){
		double[] edge1 = getEdge(buffered1);
		double[] edge2 = getEdge(buffered2);

		double edgeSim = 1 - calculateEdgeDistance(edge1, edge2);
		return edgeSim;
	}
	
	public double calculateEdgeSimilarity(double[] edge1, double[] edge2){

		double edgeSim = 1 - calculateEdgeDistance(edge1, edge2);
		return edgeSim;
	}
	
	public double computeSimilarity(double[] edge1, double[] edge2, double[][] ccv1, double[][] ccv2) {

		double edgeSim = calculateEdgeSimilarity(edge1, edge2);
		double ccvSim = calculateCCVSimilarity(ccv1, ccv2);
		if(edgeSim < 0.8)
			edgeSim = 0;
		if(edgeSim>threshold)
			return edgeSim;
		else if(ccvSim > threshold)
			return ccvSim;
		else
			return (0.6*ccvSim+0.4*edgeSim);
	}
	

	
	public double[][] applyFilter(double[][] bin, boolean isVert)
	{
		double[][] result = new double[bin.length][bin[0].length];
		double[][] vertfilter = {{-1,0,1},{2,0,-2},{-1,0,1}};
		double[][] horifilter = {{1,2,1},{0,0,0},{-1,-2,-1}};
		double[][] filter;
		if(isVert)
			filter = vertfilter;
		else
			filter = horifilter;
		for(int i = 0; i < result.length -3; i++){
			for(int j = 0; j < result[0].length -3; j++){
				// apply mask
				double sum = 0;
				for(int y = i; y < i+3; y++){
					for(int x = j; x < j+3; x++){
						sum += filter[y-i][x-j] * bin[y][x];
					}
				}
				result[i+1][j+1] = sum/4;
			}
		}
		return result;
	}
	
	public int quantilizeGradient(double rawData){
		if(rawData < Math.PI/6)
			return 0;
		else if(rawData  < Math.PI/4)
			return 1;
		else if(rawData < Math.PI /3)
			return 2;
		else if(rawData < Math.PI/2)
			return 3;
		else if(rawData < 2*Math.PI/3)
			return 4;
		else if(rawData < 3*Math.PI/4)
			return 5;
		else if(rawData < 5*Math.PI/6)
			return 6;
		else if(rawData < Math.PI)
			return 7;
		else if(rawData < 7*Math.PI /6)
			return 8;
		else if(rawData < 5*Math.PI/4)
			return 9;
		else if(rawData < 4*Math.PI/3)
			return 10;
		else if(rawData < 3*Math.PI/2)
			return 11;
		else if(rawData < 5*Math.PI/3)
			return 12;
		else if(rawData < 7*Math.PI/4)
			return 13;
		else if(rawData < 11*Math.PI/6)
			return 14;
		else
			return 15;
		
	}
	public double[] calculateEdge(double [][] processedImageY, double[][] processedImageX){
		double[] info = new double[magitude*gradient+1];
		double count = processedImageY.length * processedImageY[0].length;
		for(int i = 0; i < processedImageX.length; i++){
			for(int j = 0; j < processedImageX[0].length; j++){
				if(processedImageY[i][j] == 0 && processedImageX[i][j] == 0)
					info[magitude*gradient]+=1/count;
				else{
						int grad = quantilizeGradient(Math.atan2(processedImageY[i][j],processedImageX[i][j]));
						int mag = (int)Math.sqrt(Math.pow(processedImageX[i][j],2) + Math.pow(processedImageY[i][j],2)); 
						info[mag*gradient+grad]+= 1/count;
					}
				
			}
		}
		
		return info;

	}
	
	public double[] getEdge(BufferedImage image) {
		int imHeight = image.getHeight();
        int imWidth = image.getWidth();
        double[][] bins = new double[imHeight][imWidth];
        int step = 256 / dim;
        Raster raster = image.getRaster();
        for(int i = 0; i < imWidth; i++)
        {
            for(int j = 0; j < imHeight; j++)
            {
            	// rgb->ycrcb
            	int r = raster.getSample(i,j,0);
            	int g = raster.getSample(i,j,1);
            	int b = raster.getSample(i,j,2);
            	int y  = (int)( 0.299   * r + 0.587   * g + 0.114   * b);
        		
        		int ybin = y / step;
                bins[j][i] = ybin;

            }
        }
        return calculateEdge(applyFilter(bins, true), applyFilter(bins, false));

	}

	public double calculateEdgeDistance(double[] img1, double[] img2){

        // Bhattacharyya distance
		double h1 = 0.0;
		double h2 = 0.0;
		int N1 = img1.length;
        for(int i = 0; i < N1; i++) {
        	h1 = h1 + img1[i];
        	h2 = h2 + img2[i];
        }

        double Sum1 = 0.0;
        for(int i = 0; i < N1; i++) {
           Sum1 = Sum1 + Math.sqrt(img1[i]*img2[i]);
        }
        double dist1 = Math.sqrt( 1 - Sum1 / Math.sqrt(h1*h2));
        return dist1;

	}
	
	public ArrayList<SearchOutCome> feedback(BufferedImage bufferedQueryImg,ArrayList<String> fileNames){
		Map<String, Integer> feedbackResult = new HashMap<String, Integer>();
		ArrayList<SearchOutCome>topTags = new ArrayList<SearchOutCome>();
		for(int i=0; i < fileNames.size(); i++){
			File file = new File(fileNames.get(i));
			try {
				ArrayList<String> tags = readTextFile(file);
				for(int j=0; j < tags.size(); j++){
					Integer freq = feedbackResult.get(tags.get(j));
					feedbackResult.put(tags.get(j), (freq==null)? 1 : freq+1);
				}
				topTags = getTopTags(4, feedbackResult);
				ArrayList<SearchOutCome> result = (ArrayList<SearchOutCome>) searchLibrary(bufferedQueryImg,topTags);
				//System.out.println(result.size());
				return result;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return topTags;
	}
	
	public ArrayList<SearchOutCome> getTopTags(int n, Map<String, Integer> map){
		ArrayList<SearchOutCome> result = new ArrayList<SearchOutCome>();
		if(map.size() < n)
			n = map.size();
		while(n>0){
			int max = 0;
			Object key = new Object();
			Iterator it = map.entrySet().iterator();
			while(it.hasNext()){
				Map.Entry entry = (Map.Entry)it.next();
				if(Integer.parseInt(entry.getValue().toString()) > max)
					max = Integer.parseInt(entry.getValue().toString()) ;
			}
			Iterator it2 = map.entrySet().iterator();
			while(it2.hasNext()){
				Map.Entry entry = (Map.Entry)it2.next();
				if(Integer.parseInt(entry.getValue().toString()) == max){
					result.add(new SearchOutCome(entry.getKey().toString(),max));
					key = entry.getKey();
					break;
				}
			}
			map.remove(key);
			//System.out.println("removed key " + key.toString());
			
			n--;
		}
		return result;
	}
	
	public Map<String, Double> luceneSearch(int noOfTopDocs, String queryString) throws IOException, ParseException{
		FSDirectory idx = FSDirectory.open(new File("index-directory"));
		DirectoryReader ireader = DirectoryReader.open(idx);
		IndexSearcher searcher = new IndexSearcher(ireader);
		Analyzer analyzer = new EnglishAnalyzer(Version.LUCENE_CURRENT);
		Query query = new QueryParser(Version.LUCENE_CURRENT, "content", analyzer).parse(queryString);
		
		Similarity similarity = null;
		similarity = new DefaultSimilarity();

		
    	searcher.setSimilarity(similarity);
		TopDocs topDocs = searcher.search(query, noOfTopDocs);

		ScoreDoc[] scoreDocs = topDocs.scoreDocs;

		Map<String, Double>actualResult = new HashMap<String, Double>();
		for (int i = 0; i < scoreDocs.length; i++) {
			ScoreDoc hit = scoreDocs[i];
			Document doc = searcher.doc(scoreDocs[i].doc); 
			Double freq = actualResult.get(doc.get("name"));
			actualResult.put(doc.get("name"), (freq==null)?hit.score : freq + hit.score);
			//SearchOutCome r = new SearchOutCome(doc.get("name"), hit.score);
			//actualResult.add(r);
		}
		return actualResult;
	}
	
	public void luceneIndex(File folder) throws IOException{
		Analyzer analyser = null;
    	analyser  = new EnglishAnalyzer(Version.LUCENE_CURRENT);
        Similarity similarity = new DefaultSimilarity();

    	
		final File docDir = new File("index-directory");
        if (docDir.exists()) {
            deleteDirectory(docDir);
        }
    	FSDirectory idx = FSDirectory.open(new File("index-directory"));
		IndexWriterConfig indexWriterConfig = new IndexWriterConfig(
				Version.LUCENE_CURRENT, analyser);
		indexWriterConfig.setSimilarity(similarity);
		IndexWriter indexWriter = new IndexWriter(idx, indexWriterConfig);
		
		//perform index
		File[] files = folder.listFiles();
        if(null!=files){
            for(int i=0; i<files.length; i++) {
            	if(files[i].isFile() && files[i].getName().endsWith(".txt")){
	               System.out.println("indexing "+files[i].getName());
	            	try {
						BufferedReader br = new BufferedReader(new FileReader(files[i]));
						StringBuilder sb = new StringBuilder();
						String line = br.readLine();
						while (line != null){
							String trim = line.replaceAll("\\s+","");
							String regex = "[0-9]+";
							if (trim.matches(regex)) {
								break;
							}
							sb.append(line);
							sb.append('\n');
							line = br.readLine();
							
						}
						String content = sb.toString();
						System.out.println(content);
						indexFile(content, files[i].getName(),indexWriter);
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
            	}
        	}
        }
        if (indexWriter != null) {
            indexWriter.close();
        }
    }
	
    private void indexFile(String content, String fileName,IndexWriter indexWriter){
        Document doc = new Document();
        doc.add(new Field("name", fileName, Field.Store.YES, Field.Index.NOT_ANALYZED, Field.TermVector.NO));
        Field contentField = new Field("content", content, Field.Store.YES, Field.Index.ANALYZED,Field.TermVector.YES);
        doc.add(contentField);
        try {
			indexWriter.addDocument(doc);
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
	
    public static boolean deleteDirectory(File directory) {
        if(directory.exists()){
            File[] files = directory.listFiles();
            if(null!=files){
                for(int i=0; i<files.length; i++) {
                    if(files[i].isDirectory()) {
                        deleteDirectory(files[i]);
                    }
                    else {
                        files[i].delete();
                    }
                }
            }
        }
        return(directory.delete());
    }

}


/**
 * Helper Class
 *
 */
class SearchOutCome implements Comparable{
	String fileName;
	double score;
	
	public SearchOutCome(String fileName, double score){
		this.fileName = fileName;
		this.score = score;
	}
	
	public int compareTo(Object r2){
		if(score > ((SearchOutCome)r2).score)
			return -1;
		else if (score == ((SearchOutCome)r2).score)
			return 0;
		else
			return 1;
	}
}

